﻿#pragma once
#include "pch.h"
#include "crcLib.h"
#include "hid_decoder.h"
#include "hiddecodeexception.h"
#include "packutils.h"
#include <cstdio>
#include <cstdlib>

unsigned int ONCE_DELAY = 20;
unsigned int ONE_SECONDS = 1000 / ONCE_DELAY;
/* 缓存容量1MB= 1024 * 1024 */
unsigned int CAPACITY = 1024;

hid_decoder::hid_decoder(std::shared_ptr<hid_interface> hitf,
                         std::shared_ptr<config> _cfg)
    : hidInterface(hitf), threadPool(std::make_unique<ThreadPool>(2)),
      cfg(_cfg) {
  this->downloadDir = std::string(_cfg->downloadDir);
}

hid_decoder::~hid_decoder() {
  std::cout << "hid_decoder::~hid_decoder()" << std::endl;
  stopDecoding();
}

/**
 * 开始解码
 * @brief hid_decoder::startDecoding
 */
void hid_decoder::startDecoding() {
  // 防止多线程导致不一致
  unique_lock<mutex> lock(g_MutexArgs);
  // 开始解码
  isRunning = true;

  // 生产线程
  threadPool->enqueue([&] {
    int ret = -1;
    uint timeOut = 0;

    /* 保存收到数据缓冲区 */
    std::vector<char> buf;

#if _DEBUG
    std::cout << "Producer Thread enter...\n " << std::endl;
#endif

    while (isRunning) {
      if (hidInterface == nullptr) {
        isRunning = false;
        return;
      }

      // 未打开hid设备时
      if (hidInterface->isOpen() == 0) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        continue;
      }

      try {
        buf.resize(ALLOW_LENGTH, 0);
        ret = hidInterface->read((char *)buf.data(), ALLOW_LENGTH);
      } catch (const std::exception &e) {
        std::cout << "hid read error: " << e.what();
        continue;
      }

      if (ret > 0) {
        timeOut = 0;
        put(buf);
      } else if (ret == -1) {
        timeOut = 0;
        //        hidInterface->close();
        std::shared_ptr<OnHIDErrorListener> hidErrorListener =
            errorListenerPtr.lock();
        if (hidErrorListener != nullptr) {
          hidErrorListener->onHIDError(HID_CLOSED, "HID channel closed.");
        }
      } else {
        // 是否有包阻塞问题，如果1秒钟都没有收到任何包，则关闭hid总线，通知客户端
        if (decoding) {
          timeOut++;
          if (packageIndex < packageCount && timeOut >= ONE_SECONDS) {
            timeOut = 0;
            std::shared_ptr<OnHIDErrorListener> hidErrorListener =
                errorListenerPtr.lock();
            if (hidErrorListener != nullptr) {
              hidErrorListener->onHIDError(HID_READ_TIMEOUT,
                                           "Read data timeout.");
            }
            //            hidInterface->close();
          }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(ONCE_DELAY));
      }
    }

    // 退出所有业务后，关闭HID总线
    if (hidInterface) {
      std::cout << "decoder thread exit. close hid bus." << std::endl;
      hidInterface->close();
    }

#ifdef _DEBUG
    std::cout << "Producer Thread exit...\n " << std::endl;
#endif
  });

  // 读取线程
  threadPool->enqueue([&] {
#if _DEBUG
    std::cout << "Comsumer Thread enter...\n " << std::endl;
#endif
    while (isRunning) {
      take();
    }
#if _DEBUG
    std::cout << "Comsumer Thread exit...\n " << std::endl;
#endif
  });
}

/**
 * 停止解码任务
 * @brief hid_decoder::stopDecoding
 */
void hid_decoder::stopDecoding() {
  std::unique_lock<std::mutex> lock(g_MutexArgs);
  isRunning = false;
  release();
  std::queue<std::vector<char>> empty_queue;
  buffer_queue_.swap(empty_queue);
  cv_.notify_all();
}

/**
 * 放入数据缓冲区
 * @brief hid_decoder::put
 * @param data
 */
void hid_decoder::put(std::vector<char> &data) {
  unique_lock<std::mutex> lock(g_Mutex);
  while (buffer_queue_.size() == CAPACITY && isRunning) {
#if _DEBUG
    std::cout << "Producer: buffer_queue_ is full..." << std::endl;
#endif
    cv_.wait(lock);
  }

  if (!isRunning) {
    release();
    return;
  }

  // 将数据保存到队列
  std::vector<char> temp;
  temp.assign(data.begin(), data.end());
  buffer_queue_.push(temp);

  // 通知消费者线程消费数据
  cv_.notify_one();
}

/**
 * 消费者线程
 * @brief hid_decoder::take
 */
void hid_decoder::take() {
  unique_lock<std::mutex> lock(g_Mutex);
  while (buffer_queue_.empty() && isRunning) {
#if _DEBUG
    std::cout << "Consumer: No more data in buffer_queue_..." << std::endl;
#endif
    cv_.wait(lock);
  }

  if (!isRunning) {
    release();
    return;
  }

  // 获取缓冲区队列数据
  std::vector<char> pack = buffer_queue_.front();
  try {
    buffer_queue_.pop();
    decode(pack.data(), pack.size());
  } catch (HIDDecodeException &e) {
    std::cout << "buffer_queue_ catch: " << e.errMsg << std::endl;
    std::queue<std::vector<char>> empty_queue;
    buffer_queue_.swap(empty_queue);
    std::shared_ptr<OnHIDErrorListener> hidErrorListener =
        errorListenerPtr.lock();
    if (hidErrorListener != nullptr) {
      hidErrorListener->onHIDError(HID_CLOSED, "HID channel closed.");
    }
  }
}

/**
 * 检查普通文件参数
 * @brief hid_decoder::checkFileArgs
 * @param data
 * @param length
 * @return
 */
int hid_decoder::checkFileArgs(const char *data, int size) {
  // 低16位低字节和高字节
  uchar low16low = data[2];
  uchar low16high = data[3];

  // 高16位低字节和高字节
  uchar high16low = data[4];
  uchar high16high = data[5];

  // 总包长度
  contentLength =
      low16low | low16high << 8 | high16low << 16 | high16high << 24;
  if (downloadDir.empty()) {
    std::shared_ptr<OnHIDErrorListener> hidErrorListener =
        errorListenerPtr.lock();
    if (hidErrorListener != nullptr) {
      hidErrorListener->onHIDError(HID_DECODE_ERROR, "The file path is NULL");
    }
    throw HIDDecodeException(HID_WRITE_ERROR, "The file path is NULL");
  }

  // 获取文件名
  uchar fileNameLengthLow = data[8];
  uchar fileNameLengthHigh = data[9];
  int fileNameLength = fileNameLengthLow | fileNameLengthHigh << 8;

  std::vector<char> fileNameList;
  int startIndex = getFileNameEnd(false);
  fileNameList.assign(data + startIndex, data + startIndex + fileNameLength);
  std::string fileName(fileNameList.data(), fileNameList.size());

  downloadPath = std::string(downloadDir);
  downloadPath.append("/");
  //  time_t timestamp = time(NULL);
  //  downloadPath.append(std::to_string(timestamp));
  downloadPath.append(fileName);

#if _DEBUG
  std::cout << "downloadPath: " << downloadPath << std::endl;
#endif
  std::cout << "downloadPath: " << downloadPath << std::endl;

  // 标签长度
  startIndex = getFileTagStart(false, fileNameLength);
  uchar tagLow = data[startIndex];
  uchar tagHigh = data[startIndex + 1];

  // 标签包内容
  int tagSize = tagLow | tagHigh << 8;

  // 每个包最大有效数
  int packageLength = getFileRequestBodyLength(false, fileNameLength, tagSize);

  // 计算总包个数
  packageCount = getTotalPackCount(contentLength, packageLength);

  // 打开文件
  file = fopen(downloadPath.c_str(), "wb");
  if (file == NULL) {
    return HID_DECODE_ERROR;
  }
  // 统计包索引
  packageIndex = 1;
  decoding = true;
  buffer.resize(0);

  return OK;
}

/**
 * 处理随机读写文件
 * @brief hid_decoder::checkRandomFileArgs
 * @param data
 * @param length
 * @return
 */
int hid_decoder::checkRandomFileArgs(const char *data, int size) {
  // 低16位低字节和高字节
  uchar low16low = data[2];
  uchar low16high = data[3];

  // 高16位低字节和高字节
  uchar high16low = data[4];
  uchar high16high = data[5];

  // 总包长度
  contentLength =
      low16low | low16high << 8 | high16low << 16 | high16high << 24;

  // 保存文件
  std::string fileName("output.bak");
  downloadPath = std::string(downloadDir);
  downloadPath.append("/");
  time_t timestamp = time(NULL);
  downloadPath.append(std::to_string(timestamp));
  downloadPath.append(fileName);

  // 以读写模式创建文件
  file = fopen(downloadPath.c_str(), "wb+");
  if (file == NULL) {
    return HID_DECODE_ERROR;
  }
  randomFileDecoding = true;
  packageIndex = 1;
  decoding = true;
  buffer.resize(0);

  return OK;
}

/**
 * 检查普通文本数据包参数
 * @brief hid_decoder::checkFrameArgs
 * @param data
 * @param length
 * @return
 */
int hid_decoder::checkFrameArgs(const char *data, int size) {
  // 低16位低字节和高字节
  uchar low16low = data[2];
  uchar low16high = data[3];

  // 高16位低字节和高字节
  uchar high16low = data[4];
  uchar high16high = data[5];

  // 标签长度低8位
  uchar tagLow = data[8];
  // 标签长度高8位
  uchar tagHigh = data[9];

  // 标签包内容
  int tagSize = tagLow | tagHigh << 8;

  // 总包长度
  contentLength =
      low16low | low16high << 8 | high16low << 16 | high16high << 24;
  // 总包长度为0
  if (contentLength == 0) {
    return HID_ERR;
  }

  // 文本数据包有效长度
  int packageLength = getRequestBodyLength(false, tagSize);
  // 总包个数
  packageCount = (int)getTotalPackCount(contentLength, packageLength);

  buffer.resize(0);
  packageIndex = 1;
  decoding = true;

  return OK;
}

/**
 * 解析收到的数据包
 * @brief hid_decoder::decode
 * @param data
 * @param length
 * @return
 */
int hid_decoder::decode(const char *data, int size) {
  int ret = HID_DECODE_ERROR;
  if (size == 0) {
    std::shared_ptr<OnHIDErrorListener> hidErrorListener =
        errorListenerPtr.lock();
    if (hidErrorListener != nullptr) {
      hidErrorListener->onHIDError(HID_DECODE_ERROR, "The data is NULL.");
    }
    throw HIDDecodeException(HID_DECODE_ERROR, "The data is NULL.");
  }

  // 获取文件头
  char head = data[0];
  // 获取命令
  char cmd = data[1];

  // 匹配命令是否非法
  if (!match(head, cmd)) {
    std::shared_ptr<OnHIDErrorListener> hidErrorListener =
        errorListenerPtr.lock();
    if (hidErrorListener != nullptr) {
      hidErrorListener->onHIDError(HID_DECODE_ERROR, "The data is invalid.");
    }
    throw HIDDecodeException(HID_WRITE_ERROR, "The data is NULL.");
  }

  if (cmd == CMD_RANDOM_FILE_END || cmd == CMD_RANDOM_FILE_CANCEL) {
    randomFileDecoding = false;
  } else {
    if (packageIndex == 0) {
      if (cmd == CMD_FILE) { /* 收到第一个包是文件包时检查参数 */
        if (checkFileArgs(data, size) != OK) {
          return HID_DECODE_ERROR;
        }
      } else if (
          cmd ==
          CMD_RANDOM_FILE_START) { /* 收到第一个包是随机文件包是检查参数*/
        if (!randomFileDecoding) {
          if (checkRandomFileArgs(data, size) != OK) {
            return HID_DECODE_ERROR;
          }
        }
      } else {
        // 收到的是其他文本宝包时处理
        checkFrameArgs(data, size);
      }
    }
  }

  // 解析包内容
  switch (cmd) {
  case CMD_FILE:
    INSTANCE(constants).setAckFlag(true);
    ret = decodeFile(data, size);
    break;

  case CMD_TEXT: /*文本*/
    INSTANCE(constants).setAckFlag(true);
    ret = decodeText(data, size);
    break;

  case CMD_AUDIO_FRAME: /*音频帧*/
    INSTANCE(constants).setAckFlag(true);
    ret = decodeAudioFrame(data, size);
    break;

  case CMD_VIDEO_FRAME: /*视频帧*/
    INSTANCE(constants).setAckFlag(true);
    ret = decodeVideoFrame(data, size);
    break;

  case CMD_RANDOM_FILE_START: /*随机文件开始*/
    ret = decodeRandomFile(data, size);
    break;

  case CMD_RANDOM_FILE_END: /*随机文件结束*/
    INSTANCE(constants).setAckFlag(true);
    ret = decodeRandomFileEnd(data, size);
    break;

  case CMD_RANDOM_FILE_CANCEL: /*随机文件取消*/
    INSTANCE(constants).setAckFlag(true);
    ret = decodeRandomFileCancel(data, size);
    break;

  case CMD_RANDOM_FILE_PAUSED: /* 随机文件暂停，此时文件会被一只占用 */
    INSTANCE(constants).setAckFlag(true);
    decodeRandomFilePause(data, size);
    break;

  case CMD_CANCEL: /*下位机取消任务 */
    INSTANCE(constants).setAckFlag(true);
    decodeCancel(data, size);
    break;

  case CMD_ACK: // ACK
    decodeACK(data, size);
    break;

    /* 收到下位机发送 PING  */
  case CMD_PING_PONG:
#if _DEBUG
    std::cout << "Receive PING..." << std::endl;
#endif
    release();
    break;

  default: /*收到的包格式有问题*/
    std::shared_ptr<OnHIDErrorListener> errorListener = errorListenerPtr.lock();
    if (errorListener != nullptr) {
      errorListener->onHIDError(HID_DECODE_ERROR, "Not found decoder.");
    }
    release();
    break;
  }
  return ret;
}

/**
 * 解码普通文本数据
 * @brief hid_decoder::decodeText
 * @param data
 * @param buffer
 * @param tagBuffer
 * @param length
 * @return
 */
int hid_decoder::decodeText(const char *data, int size) {
  // 获取命令
  char cmd = data[1];

  // 当前包长度
  uchar packageLengthLow = data[6];
  uchar packageLengthHigh = data[7];
  // 标签长度
  uchar tagLow = data[8];
  uchar tagHigh = data[9];

  // 获取标签长度
  int tagSize = tagLow | tagHigh << 8;

  // 获取当前包长度
  int packageLength = packageLengthLow | packageLengthHigh << 8;
  if (packageLength <= 0) {
    release();
    return HID_DECODE_ERROR;
  }

  // 获取 CRC
  int startIndex = getCrcStart(false, tagSize, packageLength);
  uint8_t crcLow8 = data[startIndex];
  uint8_t crcHigh8 = data[startIndex + 1];
  uint16_t crcIbm1 = crcLow8 | crcHigh8 << 8;
  startIndex = getPackageContentStart(false, tagSize);
  std::vector<char> crcList(data + startIndex,
                            data + startIndex + packageLength);
  uint16_t crcIbm2 =
      crc16_ibm1((uint8_t *)crcList.data(), (uint16_t)crcList.size());
  if (crcIbm1 != crcIbm2) {
    std::shared_ptr<OnHIDFrameListener> frameListener = frameListenerPtr.lock();
    if (frameListener != nullptr) {
      frameListener->onHIDFrameFailed(HID_ENCODE_ERROR, "Check CRC fail!");
    }
    release();
    return HID_DECODE_ERROR;
  }

  // 拷贝数据包
  startIndex = getPackageContentStart(false, tagSize);
  buffer.insert(buffer.end(), data + startIndex,
                data + startIndex + packageLength);

  // 包索引从1开始，总包长全部接收完毕.
  if (packageIndex >= packageCount) {
    std::shared_ptr<OnHIDFrameListener> frameListener = frameListenerPtr.lock();
    if (frameListener != nullptr) {
      startIndex = getTagEnd(false);
      std::vector<char> tagList;
      tagList.assign(data + startIndex, data + startIndex + tagSize);
      std::string tag(tagList.begin(), tagList.end());
      frameListener->onHIDFrameFrame(cmd, buffer, tag);
    }

    release();
  } else {
    totalPackageLength += packageLength;
    packageIndex++;
  }
  return OK;
}

/**
 * 解码文件
 * @brief hid_decoder::decodeFile
 * @param data
 * @param length
 * @return
 */
int hid_decoder::decodeFile(const char *data, int size) {
  // 当前数据包长度
  uchar packageLenLow = data[6];
  uchar packageLenHigh = data[7];

  // 当前包长度
  int packageLength = packageLenLow | packageLenHigh << 8;
  if (packageLength <= 0) {
    release();
    return HID_DECODE_ERROR;
  }

  // 获取文件名长度(utf-8字段)
  uchar fileLengthLow = data[8];
  uchar fileLengthHigh = data[9];

  // 文件名长度
  int fileNameLength = fileLengthLow | fileLengthHigh << 8;
  int startIndex = getFileNameEnd(false);
  std::vector<char> fileNameList;
  fileNameList.assign(data + startIndex, data + startIndex + fileNameLength);
  std::string fileName(fileNameList.begin(), fileNameList.end());

  // 获取标签长度
  std::string tag;
  startIndex = getFileTagStart(false, fileNameLength);
  uchar tagLow = data[startIndex];
  uchar tagHigh = data[startIndex + 1];
  int tagSize = tagLow | tagHigh << 8;
  std::vector<char> tagList;
  if (tagSize > 0) {
    startIndex = getFileTagEnd(false, fileNameLength);
    tagList.assign(data + startIndex, data + startIndex + tagSize);
    tag = std::string(tagList.begin(), tagList.end());
  }

  // 获取 CRC
  startIndex = getFileCrcStart(false, fileNameLength, tagSize, packageLength);
  uint8_t crcLow8 = data[startIndex];
  uint8_t crcHigh8 = data[startIndex + 1];
  uint16_t crcIbm1 = crcLow8 | crcHigh8 << 8;
  startIndex = getFilePackageContentStart(false, fileNameLength, tagSize);
  std::vector<char> crcList(data + startIndex,
                            data + startIndex + packageLength);
  uint16_t crcIbm2 =
      crc16_ibm1((uint8_t *)crcList.data(), (uint16_t)crcList.size());
  if (crcIbm1 != crcIbm2) {
    std::shared_ptr<OnHIDReadFileListener> readFileListener =
        readFileListenerPtr.lock();
    if (readFileListener != nullptr) {
      readFileListener->onHIDReadFileFailed(HID_DECODE_ERROR,
                                            "Check CRC fail!");
    }
    release();
    return HID_DECODE_ERROR;
  }

  // 拷贝文件内容到缓冲区
  std::vector<char> buffer;
  startIndex = getFilePackageContentStart(false, fileNameLength, tagSize);
  buffer.assign(data + startIndex, data + startIndex + packageLength);

  // 写文件内容
  int count = fwrite(buffer.data(), sizeof(char), buffer.size(), file);
  if (count != packageLength) {
    std::shared_ptr<OnHIDReadFileListener> readFileListener =
        readFileListenerPtr.lock();
    if (readFileListener != nullptr) {
      readFileListener->onHIDReadFileFailed(HID_WRITE_ERROR,
                                            "Write data error.");
    }
    remove(downloadPath.c_str());
    fclose(file);
    file = nullptr;
    release();
    return HID_DECODE_ERROR;
  }

  // 回调文件包写入结果
  std::shared_ptr<OnHIDReadFileListener> readFileListener =
      readFileListenerPtr.lock();
  if (readFileListener != nullptr) {
    readFileListener->onHIDReadFileResult(downloadPath, tag, packageIndex,
                                          packageCount,
                                          packageIndex >= packageCount);
  }

  // 统计收到的包个数
  if (packageIndex >= packageCount) {
    packageCount = 0;
    packageIndex = 0;

    fflush(file);
    fclose(file);
    file = NULL;
    release();
  } else {
    packageIndex++;
  }

  return OK;
}

/**
 * 解码音频帧数据
 * @brief hid_decoder::decodeAudioFrame
 * @param data
 * @param buffer
 * @param tagBuffer
 * @param length
 * @return
 */
int hid_decoder::decodeAudioFrame(const char *data, int size) {
  // 获取命令
  char cmd = data[1];

  // 当前包长度
  uchar packageLengthLow = data[6];
  uchar packageLengthHigh = data[7];
  // 标签长度
  uchar tagLow = data[8];
  uchar tagHigh = data[9];

  // 获取标签长度
  int tagSize = tagLow | tagHigh << 8;

  // 获取当前包长度
  int packageLength = packageLengthLow | packageLengthHigh << 8;
  if (packageLength <= 0) {
    release();
    return HID_DECODE_ERROR;
  }

  // 获取 CRC
  int startIndex = getCrcStart(false, tagSize, packageLength);
  uint8_t crcLow8 = data[startIndex];
  uint8_t crcHigh8 = data[startIndex + 1];
  uint16_t crcIbm1 = crcLow8 | crcHigh8 << 8;
  startIndex = getPackageContentStart(false, tagSize);
  std::vector<char> crcList(data + startIndex,
                            data + startIndex + packageLength);
  uint16_t crcIbm2 =
      crc16_ibm1((uint8_t *)crcList.data(), (uint16_t)crcList.size());
  if (crcIbm1 != crcIbm2) {
    std::shared_ptr<OnHIDFrameListener> frameListener = frameListenerPtr.lock();
    if (frameListener != nullptr) {
      frameListener->onHIDFrameFailed(HID_ENCODE_ERROR, "Check CRC fail!");
    }
    release();
    return HID_DECODE_ERROR;
  }

  // 拷贝数据包
  startIndex = getPackageContentStart(false, tagSize);
  buffer.insert(buffer.end(), data + startIndex,
                data + startIndex + packageLength);

  // 包索引从1开始，总包长全部接收完毕.
  if (packageIndex >= packageCount) {
    std::shared_ptr<OnHIDFrameListener> frameListener = frameListenerPtr.lock();
    if (frameListener != nullptr) {
      startIndex = getTagEnd(false);
      std::vector<char> tagList;
      tagList.assign(data + startIndex, data + startIndex + tagSize);
      std::string tag(tagList.begin(), tagList.end());
      frameListener->onHIDFrameFrame(cmd, buffer, tag);
    }

    release();
  } else {
    totalPackageLength += packageLength;
    packageIndex++;
  }
  return OK;
}

/**
 * 解码视频帧数据
 * @brief hid_decoder::decodeVideoFrame
 * @param data
 * @param buffer
 * @param tagBuffer
 * @param length
 * @return
 */
int hid_decoder::decodeVideoFrame(const char *data, int size) {
  // 获取命令
  char cmd = data[1];

  // 当前包长度
  uchar packageLengthLow = data[6];
  uchar packageLengthHigh = data[7];
  // 标签长度
  uchar tagLow = data[8];
  uchar tagHigh = data[9];

  // 获取标签长度
  int tagSize = tagLow | tagHigh << 8;

  // 获取当前包长度
  int packageLength = packageLengthLow | packageLengthHigh << 8;
  if (packageLength <= 0) {
    release();
    return HID_DECODE_ERROR;
  }

  // 获取 CRC
  int startIndex = getCrcStart(false, tagSize, packageLength);
  uint8_t crcLow8 = data[startIndex];
  uint8_t crcHigh8 = data[startIndex + 1];
  uint16_t crcIbm1 = crcLow8 | crcHigh8 << 8;
  startIndex = getPackageContentStart(false, tagSize);
  std::vector<char> crcList(data + startIndex,
                            data + startIndex + packageLength);
  uint16_t crcIbm2 =
      crc16_ibm1((uint8_t *)crcList.data(), (uint16_t)crcList.size());
  if (crcIbm1 != crcIbm2) {
    std::shared_ptr<OnHIDFrameListener> frameListener = frameListenerPtr.lock();
    if (frameListener != nullptr) {
      frameListener->onHIDFrameFailed(HID_ENCODE_ERROR, "Check CRC fail!");
    }
    release();
    return HID_DECODE_ERROR;
  }

  // 拷贝数据包
  startIndex = getPackageContentStart(false, tagSize);
  buffer.insert(buffer.end(), data + startIndex,
                data + startIndex + packageLength);

  // 包索引从1开始，总包长全部接收完毕.
  if (packageIndex >= packageCount) {
    std::shared_ptr<OnHIDFrameListener> frameListener = frameListenerPtr.lock();
    if (frameListener != nullptr) {
      startIndex = getTagEnd(false);
      std::vector<char> tagList;
      tagList.assign(data + startIndex, data + startIndex + tagSize);
      std::string tag(tagList.begin(), tagList.end());
      frameListener->onHIDFrameFrame(cmd, buffer, tag);
    }

    release();
  } else {
    totalPackageLength += packageLength;
    packageIndex++;
  }
  return OK;
}

/**
 * 解析随机文件开始
 * @brief hid_decoder::decodeRandomFile
 * @param data
 * @param buffer
 * @param tagBuffer
 * @param length
 * @return
 */
int hid_decoder::decodeRandomFile(const char *data, int size) {
  int startIndex = getRandomFileTagStart();

  // 当前包长度
  uchar packageLenLow = data[6];
  uchar packageLenHigh = data[7];

  // 有效包长由索引包+有效内容组成，索引包占4字节
  int packageLength = (packageLenLow | packageLenHigh << 8) - FILE_POS_COUNT;

  // 获取标签长度
  uchar tagLow = data[startIndex];
  uchar tagHigh = data[startIndex + 1];
  int tagSize = tagLow | tagHigh << 8;

  std::string tag;
  std::vector<char> tagList;
  if (tagSize > 0) {
    startIndex = getRandomFileTagEnd();
    tagList.assign(data + startIndex, data + startIndex + tagSize);
    tag = std::string(tagList.begin(), tagList.end());
  }

  // 获取索引包长度
  startIndex = getRandomFilePackageContentStart(tagSize);
  uchar low16low = data[startIndex];
  uchar low16high = data[startIndex + 1];

  // 高16位低字节和高字节
  uchar high16low = data[startIndex + 2];
  uchar high16high = data[startIndex + 3];

  // 找到文件索引偏移位置，将数据写入
  std::streampos offset =
      low16low | low16high << 8 | high16low << 16 | high16high << 24;

  if (offset <= 0) {
    return HID_WRITE_ERROR;
  }

  // 获取 CRC
  startIndex = getRandomFileCrCStart(tagSize, packageLength);
  std::vector<char> crcList(data + startIndex,
                            data + startIndex + packageLength);
  uint8_t crcLow8 = data[startIndex];
  uint8_t crcHigh8 = data[startIndex + 1];
  uint16_t crcIbm1 = crcLow8 | crcHigh8 << 8;
  uint16_t crcIbm2 =
      crc16_ibm1((uint8_t *)crcList.data(), (uint16_t)crcList.size());
  if (crcIbm1 != crcIbm2) {
    std::shared_ptr<OnHIDReadRandomFileListener> randomFileListener =
        randomFileListenerPtr.lock();
    if (randomFileListener != nullptr) {
      randomFileListener->onHIDReadRandomFailed(HID_DECODE_ERROR,
                                                "Check CRC fail!");
    }
    release();
    return HID_DECODE_ERROR;
  }

  // 拷贝文件内容
  std::vector<char> temp;
  startIndex = getRandomFilePackageContentStart(tagSize);
  temp.assign(data + startIndex, data + startIndex + packageLength);

  // 定位文件位置
  if (fseek(file, offset, SEEK_SET) != 0) {
    remove(downloadPath.c_str());
    fclose(file);
    file = nullptr;
    release();

    return HID_DECODE_ERROR;
  }

  // 写文件内容
  size_t count = fwrite(temp.data(), sizeof(char), packageLength, file);
  if (count != packageLength) {
    remove(downloadPath.c_str());
    fclose(file);
    file = nullptr;
    release();

    return HID_DECODE_ERROR;
  }
  // 刷新缓冲区，写入到文件中，考虑性能问题暂时先屏蔽
  //  fflush(file);

  return OK;
}

/**
 * 解析随机文件结束标志
 * @brief hid_decoder::decodeRandomFileEnd
 * @param data
 * @param length
 * @return
 */
int hid_decoder::decodeRandomFileEnd(const char *data, int size) {
  if (file != NULL) {
    fclose(file);
    file = NULL;
  }

  randomFileDecoding = false;

  // 获取标签长度
  int startIndex = getRandomFileTagStart();
  uchar tagLow = data[startIndex];
  uchar tagHigh = data[startIndex + 1];
  int tagSize = tagLow | tagHigh << 8;

  // 文件名长度
  startIndex = getRandomFilePackageContentStart(tagSize);
  int fileNameLength = data[startIndex] | data[startIndex + 1] << 8;

  // 生成文件名
  char *fileNameCStr = (char *)malloc(fileNameLength + 1);
  if (fileNameCStr == nullptr) {
    remove(downloadPath.c_str());
    return HID_ERR;
  }
  memset(fileNameCStr, 0, fileNameLength + 1);
  //    std::string fileName("_output_");
  //    fileName.append(fileNameCStr);
  startIndex += FILE_NAME_COUNT;
  memcpy(fileNameCStr, data + startIndex, fileNameLength);
  std::string fileName(fileNameCStr);
  free(fileNameCStr);

  std::string newPath = std::string(downloadDir);
  newPath.append("/");
  time_t timestamp = time(NULL);
  newPath.append(std::to_string(timestamp));
  newPath.append("_");
  newPath.append(fileName);

  // 重命名为 xxx_video.mp4
  // xxx_test.dat
  if (rename(downloadPath.c_str(), newPath.c_str()) == 0) {
    downloadPath = newPath;
  } else {
    remove(downloadPath.c_str());
    return HID_ERR;
  }

  std::shared_ptr<OnHIDReadRandomFileListener> randomFileListener =
      randomFileListenerPtr.lock();
  if (randomFileListener != nullptr) {
    randomFileListener->onHIDReadRandomFileResult(downloadPath, true);
  }
  release();

  return OK;
}

int hid_decoder::decodeRandomFilePause(const char *data, int size) {
  std::shared_ptr<OnHIDReadRandomFileListener> r = randomFileListenerPtr.lock();
  if (r != nullptr) {
    r->onHIDReadRandomPause(true);
  }
  return OK;
}

int hid_decoder::decodeRandomFileCancel(const char *data, int size) {
  if (file != NULL) {
    fclose(file);
    file = NULL;
  }

  randomFileDecoding = false;

  // 删除文件
  remove(downloadPath.c_str());

  std::shared_ptr<OnHIDReadRandomFileListener> randomFileListener =
      randomFileListenerPtr.lock();
  if (randomFileListener != nullptr) {
    randomFileListener->onHIDReadRandomCancel(downloadPath);
  }

  release();
  return OK;
}

/**
 * 下位机取消任务发送
 * @brief decodeCancel
 * @param data
 * @param size
 * @return
 */
int hid_decoder::decodeCancel(const char *data, int size) {
  // 标签长度
  uchar tagLow = data[8];
  uchar tagHigh = data[9];

  // 获取标签长度
  int tagSize = tagLow | tagHigh << 8;
  int startIndex = getPackageContentStart(false, tagSize);
  uint8_t flag = data[startIndex];
  if (flag == 0x00) {
    std::shared_ptr<OnHIDFrameListener> frameListener = frameListenerPtr.lock();
    if (frameListener != nullptr) {
      frameListener->onHIDFrameFailed(HID_TASK_CANCEL, "Task cancel...");
    }
  } else if (flag == 0x01) {
    /* 关闭文件并删除 */
    if (file != NULL) {
      fclose(file);
      remove(downloadPath.c_str());
      file = NULL;
    }

    std::shared_ptr<OnHIDReadFileListener> readFileListener =
        readFileListenerPtr.lock();
    if (readFileListener != nullptr) {
      readFileListener->onHIDReadFileFailed(HID_TASK_CANCEL, "Task cancel...");
    }
  } else if (flag == 0x02) {
    /* 关闭文件并删除 */
    if (file != NULL) {
      fclose(file);
      remove(downloadPath.c_str());
      file = NULL;
    }

    std::shared_ptr<OnHIDReadRandomFileListener> randomFileListener =
        randomFileListenerPtr.lock();
    if (randomFileListener != nullptr) {
      randomFileListener->onHIDReadRandomCancel(downloadPath);
    }
  }

  release();

  return OK;
}

/**
 * 解码ACK指令，每一个指令发送后，需要对方回复一个 ACK，该 ACK
 * 暂时不携带任何内容。 上位机发送包到下位机，下位机收到包完成时，需要返回一个
 * ACK。
 * @param data
 * @param size
 * @return
 */
int hid_decoder::decodeACK(const char *data, int size) {
  // 收到相应 ACK
  INSTANCE(constants).setAckFlag(true);
  release();
  return OK;
}

std::string hid_decoder::getDownloadFilePath() const { return downloadPath; }

void hid_decoder::release() {
  contentLength = 0;
  packageIndex = 0;
  packageCount = 0;
  totalPackageLength = 0;
  decoding = false;
}

/**
 * 匹配命令是否合法
 * @brief hid_decoder::match
 * @param head
 * @param cmd
 * @return
 */
bool hid_decoder::match(char head, char cmd) {
  if (head == (char)HEAD) {
    if (cmd == (char)CMD_TEXT || cmd == (char)CMD_FILE ||
        cmd == (char)CMD_AUDIO_FRAME || cmd == (char)CMD_VIDEO_FRAME ||
        cmd == (char)CMD_RANDOM_FILE_START ||
        cmd == (char)CMD_RANDOM_FILE_END ||
        cmd == (char)CMD_RANDOM_FILE_CANCEL ||
        cmd == (char)CMD_RANDOM_FILE_PAUSED || cmd == (char)CMD_CANCEL ||
        cmd == (char)CMD_PING_PONG || cmd == CMD_ACK) {
      return true;
    }
  }
  return false;
}

void hid_decoder::setOnHIDFrameListener(std::weak_ptr<OnHIDFrameListener> l) {
  this->frameListenerPtr = l;
}

void hid_decoder::setOnHIDErrorListener(std::weak_ptr<OnHIDErrorListener> l) {
  this->errorListenerPtr = l;
}

void hid_decoder::setOnHIDReadFileListener(
    std::weak_ptr<OnHIDReadFileListener> l) {
  this->readFileListenerPtr = l;
}

void hid_decoder::setOnHIDReadRandomFileListener(
    std::weak_ptr<OnHIDReadRandomFileListener> l) {
  this->randomFileListenerPtr = l;
}
